package suncertify.service.remote;

import suncertify.service.remote.RemoteData;
import suncertify.service.Service;
import suncertify.service.ServiceEvent;
import suncertify.db.RecordNotFoundException;
import suncertify.db.DuplicateKeyException;
import suncertify.util.Options;

import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.ConnectIOException;
import java.rmi.ConnectException;

/**
 * Implementation of Service that can be used over the network
 * through java RMI technology
 */
public class RemoteServiceImpl extends Service {
    private static final Options opts = Options.getInstance();
    private RemoteData data;
    private int columnCount;
    private long clientId;

    public RemoteServiceImpl() {

    }

    @Override
    protected String[] read(int id) throws RecordNotFoundException {
        String[] res = null;
        try {
            res = data.read(id);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
        return res;
    }

    @Override
    protected void update(Integer id, Long lock, String[] data) throws RecordNotFoundException {
        try {
            this.data.update(id, data, lock);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
    }


    @Override
    protected void delete(Integer id, Long lock) throws RecordNotFoundException {
        try {
            data.delete(id, lock);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
    }

    @Override
    protected int[] find(String[] criteria) {
        int[] res = null;
        try {
            notify(ServiceEvent.FINDING);
            res = data.find(criteria);
            notify(ServiceEvent.FOUND);
        } catch (ConnectIOException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        } catch (ConnectException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, e.getMessage());
        }
        return res;
    }

    @Override
    protected int create(String[] data) throws DuplicateKeyException {
        int id = -1;
        try {
            id = this.data.create(data);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
        return id;
    }

    @Override
    protected Long lock(Integer id) throws RecordNotFoundException {
        Long lock = -1L;
        try {
            lock = data.lock(id, clientId);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
        return lock;
    }

    @Override
    protected void unlock(int id, Long lock) throws RecordNotFoundException {
        try {
            data.unlock(id, lock);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
    }

    @Override
    public boolean isActive() {
        return data != null;
    }

    @Override
    public void init() {
        try {
            notify(ServiceEvent.INITING);
            Registry reg = LocateRegistry.getRegistry(opts.get(Options.SERVER_IP));
            data = (RemoteData) reg.lookup(RemoteData.REMOTE_NAME);
            clientId = data.getRemoteClientId();
            data.startSession(clientId);
            columnCount = data.getColumnCount();
            notify(ServiceEvent.INITED);
        } catch (NotBoundException e) {
            notify(ServiceEvent.INIT_ERROR, msg.get("service.remote.error.bind"));
        } catch (RemoteException e) {
            notify(ServiceEvent.INIT_ERROR, msg.get("service.remote.error.connect"));
        }
    }

    @Override
    public void shutdown() {
        if (data == null) {
            return;
        }
        try {
            data.closeSession(clientId);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
    }

    @Override
    public int getColumnCount() {
        return columnCount;
    }

    @Override
    public String getColumnName(int col) {
        String name = "";
        try {
            name = data.getColumnName(col);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        } catch (Exception e) {
            notify(ServiceEvent.ERROR, msg.get(e.getMessage()));
        }
        return name;
    }

    @Override
    protected void cancelLocking(Integer id) {
        try {
            notify(ServiceEvent.LOCK_CANCELLING);
            data.cancelLocking(id, clientId);
            notify(ServiceEvent.LOCK_CANCELLED);
        } catch (RemoteException e) {
            notify(ServiceEvent.ERROR, msg.get("service.remote.error.connect"));
        }
    }
}
